package singleton;

public class SingletonOne {
    public static void main(String[] args) {
        new PrivateConstruct("同一个包内可以访问");
        new Thread() {
            public void run() {
                PrivateConstruct.getInstance2();
            }
        }.start();
        new Thread() {
            public void run() {
                PrivateConstruct.getInstance2();
            }
        }.start();
    }
}

class PrivateConstruct {

    //方法一：在类加载时创建实例，但有可能用不上浪费资源
    private static PrivateConstruct singleton1 = new PrivateConstruct();

    private static PrivateConstruct singleton2 = null;

    private volatile static PrivateConstruct singleton3 = null;

    //方法二：加上sychronized
    //优点：防止多线程情况下创建多个实例,可以在需要时创建
    //缺点：影响性能，只需要在第一次创建时同步，创建成功后就不需要同步，但是加上synchronized后每次获取对象都要同步调用
    public static synchronized PrivateConstruct getInstance2() {

        if (singleton2 == null) {
            singleton2 = new PrivateConstruct();
        }

        return singleton2;
    }

    //方法三：只在第一次创建时同步，比第二种效率高。

    public static PrivateConstruct getInstance3() {

        if (singleton3 == null) {
            synchronized (SingletonOne.class) {
                if (singleton3 == null) {
                    singleton3 = new PrivateConstruct();
                }
            }
        }

        return singleton3;
    }

    public static PrivateConstruct getInstance1() {
        return singleton2;
    }

    protected PrivateConstruct(String name) {
        System.out.println("protected 构造器，只能是同包内可new访问");
    }

    private PrivateConstruct() {
        System.out.println("private 构造器，不能通过new访问，只能方法内部访问");
    }
}
